using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace Util
{
	public abstract class StreamEx : IDisposable
	{
		public abstract void Dispose();

		public abstract int Position
		{
			get;
			set;
		}

		public abstract char Read();
		public abstract void Write(char ch);
		public abstract void Insert(char ch);

		public abstract void Delete(int count);

		public IEnumerable<char> Read(int count)
		{
			for (int i = 0; i < count; i++)
				yield return Read();
		}

		public char Peek()
		{
			char res = Read();
			StepBack();
			return res;
		}

		public char? Previous()
		{
			if (Position == 0)
				return null;
			StepBack();
			char res = Read();
			return res;
		}

		public void Write(IEnumerable<char> vals)
		{
			foreach (char ch in vals)
			{
				Write(ch);
			}
		}

		public void Insert(IEnumerable<char> vals)
		{
			foreach (char ch in vals)
			{
				Insert(ch);
				Position++;
			}
		}

		public void Seek(int pos)
		{
			Position = pos;
		}

		public abstract int Length
		{
			get;
		}

		public int ItemsLeft
		{
			[DebuggerStepThrough]
			get { return Length - Position; }
		}

		public void StepBack()
		{
			Seek(Position - 1);
		}

		public void StepForward()
		{
			Seek(Position - 1);
		}

		public bool Depleted
		{
			[DebuggerStepThrough]
			get { return (Position >= Length); }
		}

		public override string ToString()
		{
			string body;
			if (!Depleted)
			{
				StringBuilder rest = new StringBuilder();
				int startPos = Position;
				foreach (char cur in Read(ItemsLeft))
					rest.Append(cur);
				Position = startPos;
				body = string.Format("rest: {0}", rest.ToString());
			}
			else
			{
				body = "depleted";
			}
			string res = String.Format("pos = {0}; {1}", Position, body);
			return res;
		}

		public string BufferToString()
		{
			int oldPos = Position;
			Seek(0);
			StringBuilder res = new StringBuilder();
			while (!Depleted)
			{
				char ch = Read();
				res.Append(ch);
			}
			Seek(oldPos);
			return res.ToString();
		}

		public TextReader AsTextReader
		{
			get { return new TextReaderAdapter(this); }
		}
	}
}
